/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "se_param_manager.h"

#include "file_ex.h"
#include "loghelper.h"

namespace OHOS {
namespace SE {
// params used for json file parsing
constexpr const int MAX_PARAM_LIST_LEN = 50;
constexpr const char* COTA_FILE_PATH =
    "/data/service/el1/public/update/param_service/install/system/etc/nfc/nfc_cota_data.json";
constexpr const char* PARAM_FILE_PATH = "system/etc/nfc/nfc_ext_params.json";

constexpr const char* KEY_SIM_PARAMS_DATA = "sim_params_data";
constexpr const char* KEY_APP_SIGNATURE_MAP = "app_signature_map";
constexpr const char* KEY_SIGNATURE_IN_SIM = "signature_in_sim";
constexpr const char* KEY_HMOS_MAPPED_SIGNATURE = "hmos_mapped_signature";

SeParamManager::SeParamManager()
{
    InfoLog("SeParamManager constructor start.");
}

SeParamManager::~SeParamManager()
{
    WarnLog("SeParamManager destructing");
}

bool SeParamManager::GetStringVectorFromJson(cJSON *paramData, const std::string &key, std::vector<std::string> &strVec)
{
    DebugLog("parsing field [%{public}s]", key.c_str());
    cJSON *jsonData = cJSON_GetObjectItemCaseSensitive(paramData, key.c_str());
    if (jsonData == nullptr || !cJSON_IsArray(jsonData)) {
        ErrorLog("fail to parse field [%{public}s]", key.c_str());
        return false;
    }
    int jsonDataSize = cJSON_GetArraySize(jsonData);
    if (jsonDataSize == 0 || jsonDataSize > MAX_PARAM_LIST_LEN) {
        ErrorLog("illegal array size [%{public}d]", jsonDataSize);
        return false;
    }
    for (int i = 0; i < jsonDataSize; i++) {
        cJSON *value = cJSON_GetArrayItem(jsonData, i);
        if (value == nullptr || !cJSON_IsString(value)) {
            ErrorLog("json value nullptr or param is not string, index[%{public}d]", i);
            return false;
        }
        DebugLog("%{public}s = %{public}s", key.c_str(), value->valuestring);
        strVec.push_back(value->valuestring);
    }
    return true;
}

bool SeParamManager::GetAppSignatureMapFromJson(cJSON *nfcParamData, bool shouldClear)
{
    DebugLog("parsing field [%{public}s]", KEY_APP_SIGNATURE_MAP);
    cJSON *jsonData = cJSON_GetObjectItemCaseSensitive(nfcParamData, KEY_APP_SIGNATURE_MAP);
    if (jsonData == nullptr) {
        WarnLog("JSON has no field [%{public}s]", KEY_APP_SIGNATURE_MAP);
        return true;
    }
    if (!cJSON_IsArray(jsonData)) {
        ErrorLog("fail to parse field [%{public}s]", KEY_APP_SIGNATURE_MAP);
        return false;
    }
    int jsonDataSize = cJSON_GetArraySize(jsonData);
    if (jsonDataSize == 0 || jsonDataSize > MAX_PARAM_LIST_LEN) {
        ErrorLog("illegal array size [%{public}d]", jsonDataSize);
        return false;
    }

    if (shouldClear) {
        appSignatureMap_.clear();
    }
    cJSON *appSignatureMapEach = nullptr;
    cJSON_ArrayForEach(appSignatureMapEach, jsonData) {
        // parse signature_in_sim
        cJSON *signatureInSim = cJSON_GetObjectItemCaseSensitive(appSignatureMapEach, KEY_SIGNATURE_IN_SIM);
        if (signatureInSim == nullptr || !cJSON_IsString(signatureInSim)) {
            ErrorLog("fail to parse field [%{public}s]", KEY_SIGNATURE_IN_SIM);
            return false;
        }

        // parse hmos_mapped_signature
        std::vector<std::string> hmosSignatureVec = {};
        if (appSignatureMap_.find(signatureInSim->valuestring) != appSignatureMap_.end()) {
            hmosSignatureVec = appSignatureMap_[signatureInSim->valuestring];
        }
        if (!GetStringVectorFromJson(appSignatureMapEach, KEY_HMOS_MAPPED_SIGNATURE, hmosSignatureVec)) {
            ErrorLog("fail to parse field [%{public}s]", KEY_HMOS_MAPPED_SIGNATURE);
            return false;
        }
        appSignatureMap_[signatureInSim->valuestring] = hmosSignatureVec;
    }

    return true;
}

void SeParamManager::RefreshParams(const std::string &filepath, bool shouldClear)
{
    std::string content;
    if (!LoadStringFromFile(filepath, content) || content.empty()) {
        ErrorLog("fail to load string from json");
        return;
    }

    cJSON *json = cJSON_Parse(content.c_str());
    if (json == nullptr) {
        ErrorLog("json content nullptr.");
        return;
    }

    cJSON *paramData = cJSON_GetObjectItemCaseSensitive(json, KEY_SIM_PARAMS_DATA);
    if (paramData == nullptr) {
        ErrorLog("paramData content nullptr.");
        cJSON_Delete(json);
        return;
    }

    if (!GetAppSignatureMapFromJson(paramData, shouldClear)) {
        ErrorLog("fail to get app_signature_map from json.");
        cJSON_Delete(json);
        return;
    }
    cJSON_Delete(json);
    InfoLog("Refresh params for se service succeed.");
}

void SeParamManager::InitializeParams()
{
    std::lock_guard<std::mutex> lock(mutex_);
    InfoLog("start to initialize params for se service.");
    RefreshParams(PARAM_FILE_PATH, true);
    RefreshParams(COTA_FILE_PATH, false);
}

std::map<std::string, std::vector<std::string>> SeParamManager::GetAppSignatureMap()
{
    std::lock_guard<std::mutex> lock(mutex_);
    return appSignatureMap_;
}
} // namespace SE
} // namespace OHOS
